#include "ChatSession.h"

#include "data/Message.pb.h"
#include "data/UserInfo.pb.h"
#include "method/Method.pb.h"
#include "method/Request.pb.h"
#include "method/Response.pb.h"
#include "mysql/MysqlUtils.h"
#include "packge/packge.h"
#include "tools.h"

#include <boost/date_time/posix_time/time_formatters.hpp>
#include <boost/mysql.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <openssl/crypto.h>
#include <string>
#include <system/System.h>
#include <vector>

using namespace boost;
using namespace boost::posix_time;

// using namespace sys;
#include <ChatServer.h>

#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <fstream>

// using namespace packet;

namespace proto {
    namespace packge {
        template <
            typename AsyncReadStream,
            typename ReadToken>
        void
        async_read(
            AsyncReadStream& iostream,
            ReadToken handler) {
            auto& ctx               = iostream.get_executor();
            Packge::shared_ptr pack = std::make_shared<Packge>();

            boost::asio::post(ctx, [&iostream, pack, handler]() {
                boost::asio::async_read(
                    iostream,
                    boost::asio::buffer(&pack->header, pack->HeaderLength),
                    [&iostream, pack, handler](boost::system::error_code ec, std::size_t size) {
                        if (ec) {
                            std::cerr << "read body:" << ec.what() << std::endl;
                            handler(ec, pack);
                            return;
                        }

                        auto& header = pack->header;
                        if (
                            header.body_length <= 0 ||
                            header.version != proto::packge::VERSION10 ||
                            header.proto_type != proto::packge::ProtoBuf) {
                            std::cerr << "error proto: " << std::endl;
                            handler(ec, pack);
                            return;
                        }
                        // std::cout << "body_length:" << header.body_length << std::endl;
                        // std::cout << "version:" << (int)header.version << std::endl;
                        // std::cout << "proto_type:" << (int)header.proto_type << std::endl;

                        pack->data.resize(pack->header.body_length);
                        boost::asio::async_read(iostream, boost::asio::buffer(pack->data.data(), pack->header.body_length),
                            [&iostream, pack, handler](boost::system::error_code ec, std::size_t size) {
                                if (ec) {
                                    std::cerr << "read body:" << ec.what() << std::endl;
                                    handler(ec, pack);
                                    return;
                                }
                                handler(ec, pack);
                            });
                    });
            });
        }

        template <
            typename AsyncReadStream,
            typename ReadToken>
        void
        async_send(
            AsyncReadStream& iostream,
            Packge::shared_ptr pack,
            ReadToken handler) {
            auto& ctx = iostream.get_executor();

            boost::asio::post(ctx, [&iostream, pack, handler]() {
                auto sendbuff = boost::make_shared<std::string>();
                pack->SerializeToString(*sendbuff);
                async_write(iostream, boost::asio::buffer(sendbuff->data(), sendbuff->size()),
                    [&iostream, pack, handler](boost::system::error_code ec, std::size_t size) {
                        handler(ec, size);
                    });
            });
        }
    }  // namespace packge
}  // namespace proto

ChatSession::ChatSession(boost::asio::io_context& io_context, tcp::socket _socket)
    : io_context(io_context),
      socket(std::move(_socket)) {
    initConnect();
}

ChatSession::~ChatSession() {
    std::cout << "~ChatSession" << std::endl;
}

void ChatSession::async_read() {
    auto self(shared_from_this());
    proto::packge::async_read(
        socket,
        [this, self](boost::system::error_code ec, packge::Packge::shared_ptr pack) {
            // 读取成功
            if (!ec) {
                try {
                    this->processPacket(pack);
                }
                catch (const std::exception& e) {
                    std::cerr << "async_read:" << e.what() << '\n';
                }
                async_read();
            }
            else if (ec == boost::asio::error::eof || ec.value() == 10054) {
                // 远程主机关闭了连接
                std::clog << "远程主机关闭了连接" << std::endl;
                unlogin();
            }
            else {
                std::cerr << "ChatSession::async_read: " << ec.what() << std::endl;
                unlogin();
            }
        });
}

void ChatSession::sendPacket(packge::Packge::shared_ptr pack) {
    // stream.async_write(pack);
    auto self(shared_from_this());
    packge::async_send(socket, pack, [self](boost::system::error_code ec, size_t size) {

    });
}

void ChatSession::sendPacket(method::Response& res) {
    auto pack = std::make_shared<packge::Packge>();
    std::string data;
    pack->encode(&res);
    pack->setType(packge::PackgeType::Response);

    sendPacket(pack);
}

// void ChatSession::sendPacket(packet::file::FilePacket& file) {
//     auto pack = std::make_shared<packge::Packge>();
//     pack->setType(packge::Packge::File);
//     auto body = file.encode();
//     pack->setBody(body);
//     sendPacket(pack);
// }

// void ChatSession::sendPacket(packet::file::FilePacketEx& file) {
//     auto pack = std::make_shared<packge::Packge>();
//     pack->setType(packge::Packge::File);
//     auto body = file.encode();
//     pack->setBody(body);
//     sendPacket(pack);
// }

void ChatSession::sendPacket(std::shared_ptr<std::string> buff) {
    // socket.write_some(boost::asio::buffer(buff->data(), buff->size()));
}

void ChatSession::processPacket(packge::Packge::shared_ptr pack) {
    switch (pack->type()) {
        case packge::PackgeType::Request:
            processRequestPacket(pack);
            break;

        case packge::PackgeType::Message:
            processMessagePacket(pack);
            break;

            // case packge::PackgeType::File:
            //     processFilePacket(pack);
            //     break;

        default:
            break;
    }
}

void ChatSession::processRequestPacket(packge::Packge::shared_ptr pack) {
    // std::string body(pack->body(), pack->bodyLenght());
    // json::value jv = json::parse(body);
    // auto req       = json::value_to<method::Request>(jv);

    proto::method::Request req;
    pack->decode(&req);

    std::cout << "Request:" << req.DebugString() << std::endl;

    switch (req.method()) {
        case method::Login: {
            // data::Account account = json::value_to<data::Account>(req.body);
            data::Account account;
            account.ParseFromString(req.data());
            std::cout << "Login:" << account.DebugString() << std::endl;
            this->onUserLogin(account);
            return;
        }

        case method::Register: {
            onRegisterUser(req);
            return;
        }
        case method::JoinGroup: {
            onJoinRoom(req);
            return;
        }
        case method::CreateRoom:
        case method::CreateGroup: {
            data::ChatRoomInfo info;
            info.ParseFromString(req.data());
            onCreateGroup(info);
            return;
        }

        case method::SetAccount: {
            onSetAccount(req);
            return;
        }
        case method::ChangUserInfo:
        case method::SetUserInfo: {
            onSetUserInfo(req);
            return;
        }
        case method::GetUserInfo: {
            onGetUserInfo(req);
            return;
        }

        case method::GetFriendList: {
            onGetFriendsList();
            return;
        }

        case method::GetRoomList: {
            onGetRoomList();
            return;
        }

        case method::GetRoomMembers:
            onGetRoomMembers(req.args().at("roomId"));

            break;
        case method::SearchAuthor:

            onSearchAuthor(req.args().at("text"));
            break;

        case method::SearchGroup:
            onSearchGroup(req.args().at("text"));

            break;

        case method::AddFriends:

            onAddFriends(req.args().at("userId"));
            break;

        case method::DelFriends:

            onDelFriends(req.args().at("userId"));
            break;

        case method::SendVerificationCode:
            onSendVerificationCode(req.data());
            break;

        case method::VerifyVerificationCode:
            onVerifyVerificationCode(req.data());
            break;

        default:
            break;
    }
}

void ChatSession::processMessagePacket(packge::Packge::shared_ptr pack) {
    // using namespace packet::message;
    // std::string js(pack->body(), pack->bodyLenght());
    // auto jv  = json::parse(js);
    // auto msg = json::value_to<data::Message>(jv);
    data::Message msg;
    pack->decode(&msg);

    // 服务端填上发送方的用户id，防止伪造或没写
    msg.set_from_user_id(m_myself.userid());

    std::clog << "[ " << msg.from_user_id() << " -> " << msg.to_user_id() << " ] : \"" << msg.text() << "\"" << std::endl;
    switch (msg.type()) {
        case data::Message_Type_PTOP: {
            auto& manager = ChatServer::getInstance().sessionManager();
            manager.sendMessage(std::move(msg));
            break;
        }

        case data::Message_Type_GROUP: {
            auto& manager = ChatServer::getInstance().roomManager();
            manager.sendMessage(std::move(msg));
            break;
        }

        default:
            break;
    }
}

void ChatSession::processFilePacket(packge::Packge::shared_ptr pack) {
    // packet::file::FilePacket filePacket{};
    // auto body = pack->getBody();
    // if (filePacket.decode(body)) {
    //     saveFile(filePacket);
    // }
    // else {
    //     response::Response res;
    //     res.method  = response::File;
    //     res.message = "上传失败";
    //     res.code    = -1;
    //     sendPacket(res);
    // }
}

void ChatSession::onUserLogin(data::Account account) {
    data::Account dataAccount = account;
    method::Response respose;
    respose.set_method(::proto::method::Method::Login);
    respose.set_status(false);
    respose.set_message("");
    // 如果结果为空表示用户名错误
    if (!getAcount(dataAccount)) {
        respose.set_status(false);
        respose.set_error_code(1);
        respose.set_message("用户不存在");
    }
    else {
        // 密码正确，登录成功
        if (account.password() == dataAccount.password()) {
            getUserInfo(dataAccount.userid(), m_myself);

            if (login()) {
                // 返回信息给客户端

                respose.set_status(true);
                respose.set_message("登录成功");
                respose.set_data(m_myself.SerializeAsString());
            }
            else {
                respose.set_error_code(2);
                respose.set_message("已在其他地方登录");
                respose.set_data(m_myself.SerializeAsString());
            }
        }
        else {
            respose.set_error_code(3);
            respose.set_message("密码错误");
        }
    }

    sendPacket(respose);
}

void ChatSession::onGetFriendsList() {
    std::vector<data::FriendInfo> friendsList;
    int count = MysqlUtils::getFriends(m_myself.userid(), friendsList);
    method::Response res;
    res.set_method(::proto::method::Method::GetFriendList);

    if (count > 0) {
        json::array jsonArray;
        for (auto&& i : friendsList) {
            // jsonArray.push_back(json::value_from(i));
            res.add_datas(i.SerializeAsString());
        }

        res.set_error_code(0);
        res.set_message("成功");
        // res.set_data(json::serialize(jsonArray));
    }
    else {
        res.set_error_code(-1);
        res.set_message("用户[" + m_myself.userid() + "] 获取好友失败");
        std::clog << "用户[" << m_myself.userid() << "] 没有好友" << std::endl;
    }

    sendPacket(res);
}

void ChatSession::onGetRoomList() {
    std::vector<data::ChatRoomInfo> rooms;

    int count = MysqlUtils::getRooms(m_myself.userid(), rooms);

    method::Response res;
    res.set_method(::proto::method::Method::GetRoomList);

    if (count > 0) {
        json::array jsonArray;
        for (auto&& i : rooms) {
            // jsonArray.push_back(json::value_from(i));
            res.add_datas(i.SerializeAsString());
        }

        res.set_error_code(0);
        res.set_message("成功");
        res.set_data(json::serialize(jsonArray));
    }
    else {
        res.set_error_code(-1);
        res.set_message("用户[" + m_myself.userid() + "] 获取群聊失败");
        std::clog << "用户[" << m_myself.userid() << "] 没有加入任何群聊" << std::endl;
    }

    sendPacket(res);
}

void ChatSession::onRegisterUser(method::Request& req) {
    method::Response res;
    res.set_method(::proto::method::Method::Register);
    res.set_status(false);
    res.set_error_code(-1);
    res.set_message("失败");

    if (isVerifyVerificationCode) {
        res.set_message("请先验证邮箱或电话");
        res.set_error_code(-2);
        sendPacket(res);
        return;
    }

    data::UserInfo userInfo;
    data::Account account;
    data::RegisterInfo registerInfo;
    registerInfo.ParseFromString(req.data());

    account.set_account(registerInfo.account());
    account.set_password(registerInfo.password());

    if (MysqlUtils::registerUser(userInfo, account)) {
        res.set_error_code(0);
        res.set_status(true);
        res.set_message("注册成功");
        res.set_data(userInfo.SerializeAsString());

        isVerifyVerificationCode = false;
        verficatonCode           = 0;
    }
    else {
        res.set_message(MysqlUtils::lastError());
    }

    sendPacket(res);
}

void ChatSession::onSetAccount(method::Request& req) {
    method::Response res;
    res.set_method(::proto::method::Method::SetAccount);
    res.set_error_code(-1);
    res.set_message("失败");

    data::Account account;
    account.ParseFromString(req.data());

    if (isLogin() && account.userid() == m_myself.userid()) {
        if (MysqlUtils::setAcount(account)) {
            res.set_error_code(0);
            res.set_message("修改成功");
        }
        else {
            res.set_error_code(-1);
            res.set_message(lastError());
        }
    }
    else {
        res.set_error_code(-1);
        res.set_message("无效凭证");
    }
    sendPacket(res);
}
void ChatSession::onSetUserInfo(method::Request& req) {
    method::Response res;
    res.set_method(::proto::method::Method::SetUserInfo);
    res.set_error_code(-1);
    res.set_message("失败");

    data::UserInfo userinfo;
    userinfo.ParseFromString(req.data());
    if (isLogin() && userinfo.userid() == m_myself.userid()) {
        if (MysqlUtils::setUserInfo(userinfo)) {
            res.set_error_code(0);
            res.set_message("修改成功");
            res.set_data(userinfo.SerializeAsString());
        }
        else {
            res.set_error_code(-1);
            res.set_message(lastError());
        }
    }
    else {
        res.set_error_code(-1);
        res.set_message("无效凭证");
    }
    sendPacket(res);
}

void ChatSession::onGetUserInfo(method::Request& req) {
    method::Response res;
    res.set_method(::proto::method::Method::GetUserInfo);
    res.set_error_code(-1);
    res.set_message("失败");
    // auto userId = json::value_to<std::string>(req.body);

    auto userId = req.args().at("userId");

    data::UserInfo userinfo;

    if (MysqlUtils::getUserInfo(userId, userinfo)) {
        res.set_error_code(0);
        res.set_message("获取成功");
        res.set_data(userinfo.SerializeAsString());
    }
    else {
        res.set_error_code(-1);
        res.set_message(lastError());
    }
    sendPacket(res);
}

void ChatSession::onJoinRoom(method::Request& req) {
    auto room_id      = req.args().at("room_id");
    auto& app         = ChatServer::getInstance();
    auto& roomManager = app.roomManager();

    method::Response res;
    res.set_method(::proto::method::Method::JoinGroup);
    res.set_error_code(-1);
    res.set_message("失败");
    auto room = roomManager.getChatRoom(room_id);
    if (room) {
        room->join(myself().userid());
        res.set_error_code(0);
        res.set_message("成功");
        res.set_status(true);

        res.set_data(room->getInfomation().SerializeAsString());
    }
    sendPacket(res);
}

void ChatSession::onCreateGroup(data::ChatRoomInfo& roomInfo) {
    roomInfo.set_userid(myself().userid());
    auto& manger = ChatServer::getInstance().roomManager();
    auto status  = manger.createChatRoom(roomInfo);
    method::Response res;
    res.set_error_code(-1);
    res.set_status(false);
    res.set_message("失败");

    if (status) {
        res.set_error_code(0);
        res.set_status(true);
        res.set_message("成功");
        res.set_data(roomInfo.SerializeAsString());
    }

    sendPacket(res);
}

void ChatSession::onGetRoomMembers(std::string roomId) {
    auto& manager = ChatServer::getInstance().roomManager();
    auto room     = manager.getChatRoom(roomId);
    auto users    = room->getMembers();
    method::Response res;
    res.set_error_code(0);
    res.set_status(true);
    res.set_data(roomId);
    res.set_method(::proto::method::Method::GetRoomMembers);
    for (auto&& i : users) {
        res.add_datas(i.SerializeAsString());
    }

    sendPacket(res);
}

void ChatSession::onSearchAuthor(std::string text) {
    std::vector<data::UserInfo> users;
    int size = MysqlUtils::searchAutor(text, users);

    method::Response res;
    res.set_status(false);
    res.set_error_code(-1);
    res.set_method(::proto::method::Method::SearchAuthor);
    res.set_message("没有找到符合条件的用户");

    if (size) {
        res.set_status(true);
        res.set_error_code(0);
        res.set_message("成功");
        for (auto&& i : users) {
            res.add_datas(i.SerializeAsString());
        }
    }
    sendPacket(res);
}

void ChatSession::onSearchGroup(std::string text) {
    std::vector<data::ChatRoomInfo> groups;
    int size = MysqlUtils::searchGroup(text, groups);

    method::Response res;
    res.set_status(false);
    res.set_error_code(-1);
    res.set_method(::proto::method::Method::SearchGroup);
    res.set_message("没有找到符合条件的群");

    if (size) {
        res.set_status(true);
        res.set_error_code(0);
        res.set_message("成功");
        for (auto&& i : groups) {
            res.add_datas(i.SerializeAsString());
        }
    }
    sendPacket(res);
}

void ChatSession::onAddFriends(std::string userid) {
    proto::method::Response res;
    res.set_method(::proto::method::AddFriends);

    data::UserInfo userinfo;
    if (getUserInfo(userid, userinfo)) {
        data::FriendInfo info;
        info.set_userid(userinfo.userid());
        info.set_account(userinfo.account());
        info.set_name(userinfo.name());
        info.set_sign(userinfo.sign());
        info.set_age(userinfo.age());
        info.set_sex(userinfo.sex());
        info.set_address(userinfo.address());
        info.set_phonenumber(userinfo.phonenumber());
        info.set_email(userinfo.email());
        info.set_headshot(userinfo.headshot());
        info.set_birthday(userinfo.birthday());
        info.set_group("默认分组");

        auto datetime = second_clock::local_time();
        info.set_acquaintancetime(to_simple_string(datetime));

        // MysqlUtils::getFriendInfo(myself().userid(), userid, info);
        MysqlUtils::addFriends(myself().userid(), userid);

        res.set_status(true);
        res.set_error_code(0);
        res.set_message("你们已经是好友啦，现在可以开始聊天");
        res.set_data(info.SerializeAsString());
    }
    else {
        res.set_status(false);
        res.set_error_code(-1);
        res.set_message("用户不存在");
    }
    sendPacket(res);
}

void ChatSession::onDelFriends(std::string userid) {
    proto::method::Response res;
    res.set_method(::proto::method::DelFriends);
    res.set_status(true);
    res.set_error_code(0);
    res.set_message("删除好友成功");
    res.set_data(userid);
    MysqlUtils::delFriends(myself().userid(), userid);
    sendPacket(res);
}

void ChatSession::onSendVerificationCode(std::string bind) {
    proto::method::Response res;
    res.set_method(::proto::method::SendVerificationCode);
    res.set_status(false);
    res.set_error_code(-1);
    res.set_message("错误的邮箱");

    verficatonCode         = tools::generateVerificationCode();
    verficationCodeTimeout = std::chrono::system_clock::now();

    if (tools::sendVerificationCode(bind, std::to_string(verficatonCode))) {
        res.set_error_code(0);
        res.set_status(true);
        res.set_message("验证已发送到邮箱");
        // 将 time_point 转换为 time_t
        std::time_t time_t_value = std::chrono::system_clock::to_time_t(verficationCodeTimeout);

        // 将 time_t 转换为 Boost posix_time
        boost::posix_time::ptime ptime = boost::posix_time::from_time_t(time_t_value);

        // 格式化 ptime 为字符串
        auto str = boost::posix_time::to_simple_string(ptime);
        std::cout << "verficationCodeTimeout:" << str << std::endl;
        res.set_data(str);
    }
    sendPacket(res);
}

void ChatSession::onVerifyVerificationCode(std::string code) {
    proto::method::Response res;
    res.set_method(::proto::method::VerifyVerificationCode);
    res.set_status(false);
    res.set_error_code(-1);
    res.set_message("验证码错误");

    auto now = std::chrono::system_clock::now();
    if (now - verficationCodeTimeout > std::chrono::minutes(5)) {
        res.set_error_code(2);
        res.set_message("验证已过期");
        sendPacket(res);
        return;
    }

    if (std::stoi(code) == verficatonCode) {
        res.set_status(true);
        res.set_error_code(0);
        res.set_message("验证码正确");
    }
    sendPacket(res);
}

bool ChatSession::isLogin() {
    auto& manager = ChatServer::getInstance().sessionManager();
    if (manager.isLogin(m_myself.userid()))
        return true;
    return false;
}

bool ChatSession::login() {
    auto& manager = ChatServer::getInstance().sessionManager();
    if (manager.isLogin(m_myself.userid()))
        return false;
    manager.login(this->shared_from_this());
    return true;
}

void ChatSession::unlogin() {
    auto& manager = ChatServer::getInstance().sessionManager();
    if (manager.isLogin(m_myself.userid()))
        manager.unlogin(this->shared_from_this());
}

void ChatSession::initConnect() {
    auto& manager = ChatServer::getInstance().roomManager();
}

static size_t fileSize(std::fstream& f) {
    auto now = f.tellg();
    f.seekg(0, std::ios::end);
    auto end = f.tellg();
    f.seekg(now);
    return end;
}

#if 0
void ChatSession::onGetFile(std::string fileurl) {
    packet::file::FilePacket filePack;
    filePack.info.url = fileurl;
    auto& info        = filePack.info;

    auto p_type          = info.url.find_last_of('.');
    auto p_name          = info.url.find_last_of('/');
    info.type            = info.url.substr(p_type);
    info.name            = info.url.substr(p_name);
    info.packId          = 0;
    size_t MaxPacketSize = packet::file::FilePacket::MaxPacketSize;

    std::fstream fin(sys::to_local(fileurl), std::ios::in | std::ios::binary);
    if (fin.is_open()) {
        auto filesize = fileSize(fin);
        info.fileSize = filesize;
        if (filesize < MaxPacketSize) {
            info.packCount = 1;
            loadFile(filePack);
            sendPacket(filePack);
        }
        else {
            info.packCount = filesize / MaxPacketSize;
            if (filesize % MaxPacketSize)
                info.packCount += 1;
            size_t sendSize = 0;
            filePack.fileContent.resize(MaxPacketSize);
            for (info.packId = 0; info.packId < info.packCount; info.packId++) {
                int read_size = std::min(info.fileSize - sendSize, MaxPacketSize);
                if (read_size != MaxPacketSize)
                    filePack.fileContent.resize(read_size);
                fin.read(filePack.fileContent.data(), read_size);
                sendSize += read_size;
                std::cout << "packId:" << info.packId << std::endl;
                sendPacket(filePack);
            }
        }
    }
    fin.close();
}

void ChatSession::onGetFileEx(std::string url) {
    packet::file::FilePacketEx pack;

    auto& info = pack.info;
    info.url   = url;

    auto p_type    = info.url.find_last_of('.');
    auto p_name    = info.url.find_last_of('/');
    info.type      = info.url.substr(p_type);
    info.name      = info.url.substr(p_name);
    info.packId    = 0;
    info.packCount = 0;

    std::fstream fin(sys::to_local(url), std::ios::in | std::ios::binary);
    if (fin.is_open()) {
        auto filesize        = fileSize(fin);
        info.fileSize        = filesize;
        size_t MaxPacketSize = 32768;

        sendPacket(pack);

        {
            if (filesize % MaxPacketSize)
                info.packCount += 1;
            size_t sendSize = 0;
            while (sendSize <= filesize) {
                auto buff = std::make_shared<std::vector<char>>();

                auto readSize = std::min(MaxPacketSize, filesize - sendSize);
                buff->resize(readSize);
                fin.read(buff->data(), readSize);
                sendPacket(buff);
                sendSize += readSize;
            }
        }
    }
    fin.close();
}

bool createEmptyFile(const std::string& filename, std::size_t fileSizeInBytes) {
    // 提取路径中的目录
    fs::path directoryPath = fs::path(sys::to_local(filename)).parent_path();

    // 判断目录是否存在，不存在则创建他
    if (!fs::exists(directoryPath)) {
        if (!fs::create_directories(directoryPath)) {
            std::cerr << "Error creating directory: " << directoryPath.string() << std::endl;
            return false;
        }
    }

    std::ofstream outFile(sys::to_local(filename), std::ios::binary);

    if (!outFile.is_open()) {
        std::cerr << "Error opening file for writing: " << filename << std::endl;
        return false;
    }

    // Seek to the desired size of the file
    outFile.seekp(fileSizeInBytes - 1, std::ios::beg);

    // Write a single byte to the end of the file
    outFile.write("", 1);

    // Close the file
    outFile.close();
    return true;
}

bool ChatSession::saveFile(packet::file::FilePacket& pack) {
    packet::file::FileInfo& info = pack.info;
    auto& content                = pack.fileContent;

    gregorian::date dateToday = gregorian::day_clock::local_day();
    auto today                = gregorian::to_iso_extended_string(dateToday);

    info.url = "files/" + openssl::MD5(m_myself.userid()) + '/' + today + '/' + info.name;

    if (info.packId == 0) {
        std::clog << "file :{" << std::endl;
        std::clog << '\t' << "name        :" << info.name << std::endl;
        std::clog << '\t' << "fileSize    :" << info.fileSize << std::endl;
        std::clog << '\t' << "hashcode    :" << info.hashcode << std::endl;
        std::clog << '\t' << "packCount   :" << info.packCount << std::endl;
        std::clog << '\t' << "packId      :" << info.packId << std::endl;
        std::clog << "}" << std::endl;

        std::clog << "saveFile:"
                  << "[" << info.url << "] "
                  << "(" << info.packCount << "/" << info.packId + 1 << ")" << std::endl;
        if (!createEmptyFile(info.url, info.fileSize)) {
            return false;
        }
    }

    static std::map<std::string, std::ofstream*> streams;
    std::ofstream* fout = nullptr;
    if (info.packId == 0) {
        fout = new std::ofstream(sys::to_local(info.url), std::ios::in | std::ios::out | std::ios::binary);

        if (fout->is_open()) {
            streams[info.hashcode] = fout;
        }
    }
    else {
        fout = streams[info.hashcode];
    }

    fout->seekp(pack.MaxPacketSize * info.packId, std::ios::beg);
    fout->write(content.data(), content.size());

    if (info.packId >= info.packCount - 1) {
        streams.erase(info.hashcode);
        fout->close();
        delete fout;

        response::Response res;
        res.method  = response::File;
        res.code    = 0;
        res.message = "上传成功";
        res.body    = json::value_from(info);

        auto hashcode = openssl::GetFileHash(sys::to_local(info.url), openssl::Algorithm::MD5);
        if (hashcode != info.hashcode) {
            res.code    = -1;
            res.message = "上传失败，文件损坏";
        }

        sendPacket(res);
    }
    return true;
}

bool ChatSession::loadFile(packet::file::FilePacket& pack) {
    packet::file::FileInfo& info = pack.info;
    auto& content                = pack.fileContent;
    std::ifstream fin;
    fin.open(sys::to_local(info.url), std::ios::in | std::ios::binary);
    if (fin.is_open()) {
        std::stringstream buffer;       // stringstream object
        buffer << fin.rdbuf();          // read file content in stringstream object
        std::string str(buffer.str());  // store file content in a string
        content.resize(str.size());

        memcpy(content.data(), str.data(), str.size());
        return true;
    }
    else {
        std::clog << "loadFile:"
                  << "没有这个文件 [" << info.url << "]" << std::endl;
    }

    return false;
}

#endif

void ChatSession::start() {
    async_read();
}

void ChatSession::deliver(data::Message msg) {
    auto pack = std::make_shared<packge::Packge>();
    pack->setType(packge::PackgeType::Message);
    pack->encode(&msg);
    sendPacket(pack);
}

void ChatSession::slotOnRoomNewMessage(data::Message msg) {
    try {
        std::clog << "slotOnRoomNewMessage [" << m_myself.userid() << "]:" << msg.text() << std::endl;
        deliver(msg);
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}